package io.netty.example.a;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.*;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.locks.LockSupport;

/**
 * @author: pch
 * @description:
 * @date: 2021/5/24
 **/
public class Server {
	public static void main(String[] args) {
		/*
		NioEventLoopGroup创建流程:
			1.创建ThreadPerTaskExecutor，利用FastThreadLocalThread来提升FastThreadLocal的性能
			2.初始化children，创建一组NioEventLoop(此时未创建线程)
			3.创建EventExecutorChooser，需要时从Group中轮询出一个EventLoop来执行任务
		 */
		final NioEventLoopGroup boss = new NioEventLoopGroup(1);
		final NioEventLoopGroup worker = new NioEventLoopGroup();
		/*
		NioEventLoop流程:
			1.创建两个任务队列:taskQueue、tailTaskQueue
			2.openSelector()创建多路复用器Selector
			3.run()轮询Selector、taskQueue，串行处理IO事件和Task
		懒启动，只有在第一次execute()提交任务时才会利用executor创建线程
		对于Boss来说，线程启动是在调用bind()时，提交一个register()任务
		对于Worker，线程启动是在Boss接收到客户端连接时，提交一个register()任务
		 */
		new ServerBootstrap()
				.group(boss, worker)
				.option(ChannelOption.SO_BACKLOG, 100)
				//.attr(null,null)
				.childOption(ChannelOption.SO_TIMEOUT, 1000)
				.childOption(ChannelOption.SO_SNDBUF, 1024000)
				//.childAttr(null,null)
				.channel(NioServerSocketChannel.class)
				.childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					protected void initChannel(SocketChannel ch) throws Exception {
						ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
							@Override
							public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
								// 将接收到的数据原样写回
								//System.err.println("channelRead");
								//ctx.writeAndFlush(msg);
								/*ctx.write(Unpooled.wrappedBuffer("aa".getBytes()));
								ctx.write(Unpooled.wrappedBuffer("bb".getBytes()));
								ctx.write(Unpooled.wrappedBuffer("cc".getBytes()));
								ctx.flush();*/
								RandomAccessFile accessFile = new RandomAccessFile("/Users/panchanghe/temp/0000/html/live.html", "r");
								DefaultFileRegion region = new DefaultFileRegion(accessFile.getChannel(), 0, accessFile.length());
								ctx.writeAndFlush(region);
								/*ByteBuf buf = UnpooledByteBufAllocator.DEFAULT.heapBuffer(1024);
								buf.writeBytes("hello".getBytes());
								ctx.writeAndFlush(buf);*/
								//ReferenceCountUtil.release(msg);
							}
						});
					}
				}).bind(9999)
				.addListener(new GenericFutureListener<Future<? super Void>>() {
					@Override
					public void operationComplete(Future<? super Void> future) throws Exception {
						if (future.isSuccess()) {
							System.out.println("success");
						}
					}
				});
	}
}

class AA{
	public static void main(String[] args) {

	}
}